// import { loadEnv } from 'vite';
import isString from 'lodash/isString';
import merge from 'lodash/merge';
import type { AxiosInstance, InternalAxiosRequestConfig } from 'axios';
import { MessagePlugin } from 'tdesign-vue-next';

import hosts from '@/config/hosts';
import router from '@/router';
import { ContentTypeEnum } from '@/consts';
import { HOME_PATH, PROJECT_ID, TOKEN_NAME } from '@/config';

import type { AxiosTransform, CreateAxiosOptions } from './AxiosTransform';
import { VAxios } from './Axios';
import { joinTimestamp, formatRequestDate, setObjToUrlParams } from './utils';

//-----------------

// eslint-disable-next-line prefer-destructuring
const env = import.meta.env; // 不能这样： const { env } = import.meta;
// console.log(env);
// {
// 	"DEV": true,
// 	"PROD": false,
// 	"SSR": false
// 	"MODE": "development",
// 	"BASE_URL": "/",
// 	"VITE_MOCK_MODE": "true",
// 	"VITE_SOME_KEY": "456",
// }

const envMode = env.MODE || 'development';
const mockMode = env.VITE_MOCK_MODE === 'true';

// 如果是mock模式 或 没启用直连代理 就不配置host, 会走本地Mock拦截 或 Vite 代理
const apiHostUrl = mockMode || !hosts.isRequestProxy ? '' : hosts[envMode].api;

// 数据处理，方便区分多种处理方式
const transform: AxiosTransform = {
	// 处理请求数据。如果数据不是预期格式，可直接抛出错误
	transformRequestHook: (res, options) => {
		const { isTransformResponse, isReturnNativeResponse } = options;

		// 如果204无内容直接返回
		const method = res.config.method?.toLowerCase();
		if (res.status === 204 || method === 'put' || method === 'patch') {
			return res;
		}

		// 是否返回原生响应头 比如：需要获取响应头时使用该属性
		if (isReturnNativeResponse) {
			return res;
		}
		// 不进行任何处理，直接返回
		// 用于页面代码可能需要直接获取code，data，message这些信息时开启
		if (!isTransformResponse) {
			return res.data;
		}

		// 错误的时候返回
		const { data } = res;
		if (!data) {
			// throw new Error('请求接口错误');
			console.log(`警告！ url:${res.config.url}, `, `method:${res.config.method}, `, `msg:没有返回数据`);
			return null;
		}

		// 这里 code为 后台统一的字段，需要在 types.ts内修改为项目自己的接口返回格式
		const { code } = data;

		// 这里逻辑可以根据项目进行修改
		const hasSuccess = data && code === 0;
		if (hasSuccess) {
			return data.data;
		}

		MessagePlugin.warning(data.msg).then(() => {
			// 未获取当前用户 或 token解析失败
			if (data.code === 2 || data.code === 401) {
				localStorage.removeItem(TOKEN_NAME);
				localStorage.removeItem(PROJECT_ID);
				router.push('/login');
			} // 未获取当前项目成员
			else if (data.code === 3) {
				router.push(HOME_PATH);
			}
		});

		throw new Error(`请求接口错误, 错误码: ${code}, 错误信息: ${data.msg}`);
	},

	// 请求前处理配置
	beforeRequestHook: (config, options) => {
		const { apiUrl, isJoinPrefix, urlPrefix, joinParamsToUrl, formatDate, joinTime = true } = options;

		// 添加接口前缀
		if (isJoinPrefix && urlPrefix && isString(urlPrefix)) {
			config.url = `${urlPrefix}${config.url}`;
		}

		// 将baseUrl拼接
		if (apiUrl && isString(apiUrl)) {
			config.url = `${apiUrl}${config.url}`;
		}
		const params = config.params || {};
		const data = config.data || false;

		if (formatDate && data && !isString(data)) {
			formatRequestDate(data);
		}
		if (config.method?.toUpperCase() === 'GET') {
			if (!isString(params)) {
				// 给 get 请求加上时间戳参数，避免从缓存中拿数据。
				config.params = Object.assign(params || {}, joinTimestamp(joinTime, false));

				// add by yangkn, 把data当做prams。 为了保持统一 使用data
				if (data) config.params = Object.assign(config.params, data);
			} else {
				// 兼容restful风格
				config.url = `${config.url + params}${joinTimestamp(joinTime, true)}`;
				config.params = undefined;
			}
		} else if (!isString(params)) {
			if (formatDate) {
				formatRequestDate(params);
			}
			if (
				Reflect.has(config, 'data') &&
				config.data &&
				(Object.keys(config.data).length > 0 || data instanceof FormData)
			) {
				config.data = data;
				config.params = params;
			} else {
				// 非GET请求如果没有提供data，则将params视为data
				config.data = params;
				config.params = undefined;
			}
			if (joinParamsToUrl) {
				config.url = setObjToUrlParams(config.url as string, { ...config.params, ...config.data });
			}
		} else {
			// 兼容restful风格
			config.url += params;
			config.params = undefined;
		}
		return config as InternalAxiosRequestConfig;
	},

	// 请求拦截器处理
	requestInterceptors: (config, options) => {
		// 请求之前处理config
		const token = localStorage.getItem(TOKEN_NAME);
		// && (config as Recordable)?.requestOptions?.withToken !== false
		if (token) {
			// jwt token
			(config as Recordable).headers.Authorization = options.authenticationScheme
				? `${options.authenticationScheme} ${token}`
				: token;
		}

		// add by yangkn
		const projectId = localStorage.getItem(PROJECT_ID);
		if (projectId) {
			(config as Recordable).headers.projectId = projectId;
		}

		return config as InternalAxiosRequestConfig;
	},

	// 响应错误处理
	// 响应拦截器处理
	responseInterceptors: (res) => {
		return res;
	},
	responseInterceptorsCatch: (error: any, instance: AxiosInstance) => {
		const { config } = error;
		if (!config || !config.requestOptions.retry) return Promise.reject(error);

		config.retryCount = config.retryCount || 0;

		if (config.retryCount >= config.requestOptions.retry.count) return Promise.reject(error);

		config.retryCount += 1;

		const backoff = new Promise((resolve) => {
			setTimeout(() => {
				resolve(config);
			}, config.requestOptions.retry.delay || 1);
		});

		config.headers = { ...config.headers, 'Content-Type': ContentTypeEnum.Json };
		return backoff.then((config) => instance.request(config));
	},
};

function createAxios(opt?: Partial<CreateAxiosOptions>) {
	return new VAxios(
		merge(
			<CreateAxiosOptions>{
				// https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication#authentication_schemes
				// 例如: authenticationScheme: 'Bearer'
				authenticationScheme: 'Bearer',
				// 超时
				timeout: 30 * 1000, // modified by yangkn
				// 携带Cookie
				withCredentials: true,
				// 头信息
				headers: { 'Content-Type': ContentTypeEnum.Json },
				// 数据处理方式
				transform,
				// 配置项，下面的选项都可以在独立的接口请求中覆盖
				requestOptions: {
					// 接口地址
					apiUrl: apiHostUrl,
					// 是否自动添加接口前缀
					isJoinPrefix: true,
					// 接口前缀
					// 例如: https://www.baidu.com/api
					// urlPrefix: '/api'
					urlPrefix: '/api',
					// 是否返回原生响应头 比如：需要获取响应头时使用该属性
					isReturnNativeResponse: false,
					// 需要对返回数据进行处理
					isTransformResponse: true,
					// post请求的时候添加参数到url
					joinParamsToUrl: false,
					// 格式化提交参数时间
					formatDate: true,
					// 是否加入时间戳
					joinTime: true,
					// 忽略重复请求
					ignoreRepeatRequest: true,
					// 是否携带token
					// withToken: true, // delete by yangkn, 默认就带token
					// 重试 // 出错的情况，不再进行重试。 modified by yangkn
					// retry: {
					// 	count: 3,
					// 	delay: 1000,
					// },
				},
			},
			opt || {},
		),
	);
}
export const request = createAxios();
